package tjs.study.notes.jvm.utils.jarClash;

import sun.misc.URLClassPath;

import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Nicky.Tang on 2021/10/19 11:41 上午
 *
 * @since 02.12.10
 */
public class JarClashClassLoader extends AbtractSelfClassLoader {
    // 配置冲突jar，key-全限定类名前缀 val-这些类依赖的第三方jar
    public static final Map<String, List<String>> clashJarConfig = new HashMap<>();
    private static final Map<String, ModuleSelfClassLoader> selfClassLoaderPool = new HashMap<>();

    public JarClashClassLoader() {
        // 替换appClassloader
        super(findAppLoaderUrl(), ClassLoader.getSystemClassLoader());
    }

    private static URL[] findAppLoaderUrl() {
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        try {
            Field ucpField = classLoader.getClass().getDeclaredField("ucp");
            ucpField.setAccessible(true);
            URLClassPath urlClassPath = (URLClassPath) ucpField.get(classLoader);
            return urlClassPath.getURLs();
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("获取appClassLoader的加载路径异常");
    }

    @Override
    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        if (!name.equals("tjs.study.notes.jvm.utils.jarClash.JarClashStarter") &&
                clashJarConfig.containsKey(name)) {//todo 这里应该模糊匹配前缀
            return loadModuleSelfClass(name, resolve);
        }
        return super.loadClass(name, resolve);
    }

    private Class<?> loadModuleSelfClass(String name, boolean resolve) throws ClassNotFoundException {
        ModuleSelfClassLoader moduleSelfClassLoader = selfClassLoaderPool.get(name);
        if (moduleSelfClassLoader == null) {//todo 这里应该模糊匹配前缀,且同一个版本jar保证只加载一次
            // fixme 使用独立的类加载器去加载
            moduleSelfClassLoader = new ModuleSelfClassLoader(clashJarConfig.get(name), this.getParent());
            selfClassLoaderPool.put(name, moduleSelfClassLoader);
        }
        return moduleSelfClassLoader.loadClass(name, resolve);
    }


}
